#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <netinet/in.h>
#include <unistd.h>
#include "des.h"

#define AS_PORT 12345
#define TGS_PORT 13579
#define SS_PORT 24680

#define ClientID "xinghanting"
#define ServiceID "Tencent"

char K_client[] = "INClient";

// char ClientID[] = "xinghanting";
// char ServiceID[] = "Tecent.com";

/*
连接到服务器后，会不停循环，等待输入，
输入quit后，断开与服务器的连接
*/
struct sockaddr_in *newSocket(char *host, int port)
{
    struct sockaddr_in *serverAddr = (struct sockaddr_in *)malloc(sizeof(struct sockaddr_in));
    serverAddr->sin_family = AF_INET;
    serverAddr->sin_port = htons(port);
    serverAddr->sin_addr.s_addr = inet_addr(host);
    return serverAddr;
}

int main(int argc, char *argv[])
{
    srand(time(NULL)+1);
    time_t timestamp1 = time(NULL);
    time_t timestamp2;
    //服务器Socket
    struct socaddr_in *ASAdd = newSocket("127.0.0.1", AS_PORT);
    struct socaddr_in *TGSAdd = newSocket("127.0.0.1", TGS_PORT);
    struct socaddr_in *SSAdd = newSocket("127.0.0.1", SS_PORT);

    char sendbuffer[1000];
    char Ksession_Client_TGS[100];
    char Ksession_Client_SS[100];
    int clientSocket;
    int messageLen;

    //socket函数，失败返回-1
    //int socket(int domain, int type, int protocol);
    //第一个参数表示使用的地址类型，一般都是ipv4，AF_INET
    //第二个参数表示套接字类型：tcp：面向连接的稳定数据传输SOCK_STREAM
    //第三个参数设置为0
    if ((clientSocket = socket(AF_INET, SOCK_STREAM, 0)) < 0)
    {
        perror("ClientSocktet");
        return 0;
    }
    //判断是否连接成功
    if (connect(clientSocket, (struct sockaddr *)ASAdd, sizeof(struct sockaddr_in)) < 0)
    {
        perror("AS");
        return 0;
    }
    //如果连接成功的话，第一阶段开始,发送自己的ClientID
    printf("连接AS成功 开始第一阶段\n");
    printf("发送用户ID %s\n",ClientID);
    send(clientSocket,ClientID,strlen(ClientID),0);
    printf("发送完成\n");
    char A[200];
    printf("等待接收消息A\n");
    messageLen = recv(clientSocket,A,200,0);
    A[messageLen] = 0;
    printf("消息A接收完成\n");
    if(strcmp(A,"Please give me correct ID")==0){
        printf("认证失败，ID不符合条件\n");
        return ;
    }

    char B[200];
    printf("等待接收消息B\n");
    messageLen = recv(clientSocket,B,200,0);
    B[messageLen] = 0;
    printf("消息B接收完成\n");

    //解密消息A
    printf("解密消息A\n");
    rdes(K_client,A,messageLen,Ksession_Client_TGS);
    printf("Get Ksession_Client_TGS %s\n",Ksession_Client_TGS);

    close(clientSocket);
    printf("----------第一阶段结束----------\n");

    //生成消息C和消息D
    int i;
    char C[200];
    sprintf(C,"%s,%s",ServiceID,B);
    // printf("len of B is %d\n",strlen(B));
    // printBase64(B);
    // puts("");

    char tempD[200];
    sprintf(tempD,"<%s,%ld>",ClientID,timestamp1);
    char D[200];
    int LenOfD = des(Ksession_Client_TGS,tempD,strlen(tempD),D);
    // printf("Dlen = %d\n",LenOfD);
    // printf("消息D ");
    // printBase64(D); 
    // printf("\n");
    printf("生成消息C和消息D\n");

    if ((clientSocket = socket(AF_INET, SOCK_STREAM, 0)) < 0)
    {
        perror("ClientSocktet");
        return 0;
    }
    if (connect(clientSocket, (struct sockaddr *)TGSAdd, sizeof(struct sockaddr_in)) < 0)
    {
        perror("TGS");
        return 0;
    }
    //如果连接成功的话，第二阶段开始
    printf("连接TGS成功 开始第二阶段\n");
    //发送消息C
    printf("发送消息C\n");
    send(clientSocket,C,strlen(C),0);
    printf("发送完成\n");
    //发送信息C和信息D之间休息1秒
    sleep(2);
    //发送消息D
    printf("发送消息D\n");
    send(clientSocket,D,LenOfD,0);
    printf("发送完成\n");

    //等待接收消息E和消息F
    char E[200];
    printf("等待接收消息E\n");
    int lenOfE = recv(clientSocket,E,200,0);
    // printf("%d\n",lenOfE);
    E[lenOfE] = 0;
    // printf("加密后的消息E ");
    // printBase64(E);
    // printf("\n");
    if(strcmp(E,"Invalid ID")==0 || strcmp(E,"Invalid TGT") == 0){
        printf("认证失败，不符合条件\n");
        return ;
    }

    printf("消息E接收完成\n");

    char F[200];
    printf("等待接收消息F\n");
    int lenOfF = recv(clientSocket,F,200,0);
    F[lenOfF] = 0;
    // printf("加密后的消息F ");
    // printBase64(F);
    // printf("\n");
    printf("消息F接收完成\n");
    
    printf("解密消息F\n");
    rdes(Ksession_Client_TGS,F,lenOfF,Ksession_Client_SS);
    printf("Get Ksession_Client_SS %s\n",Ksession_Client_SS);
    close(clientSocket);
    printf("----------第二阶段结束----------\n");


    if ((clientSocket = socket(AF_INET, SOCK_STREAM, 0)) < 0)
    {
        perror("ClientSocktet");
        return 0;
    }
    if (connect(clientSocket, (struct sockaddr *)SSAdd, sizeof(struct sockaddr_in)) < 0)
    {
        perror("SS");
        return 0;
    }
    //如果连接成功的话，第三阶段开始
    printf("连接SS成功 开始第三阶段\n");
    printf("发送消息E\n");
    send(clientSocket,E,lenOfE,0);
    // printBase64(E);
    // printf("\n");
    printf("消息E发送完成\n");

    sleep(2);

    printf("发送消息G\n");
    char tempG[200];
    char G[200];
    sprintf(tempG,"<%s,%ld>",ClientID,timestamp1);
    int lenOfG = des(Ksession_Client_SS,tempG,strlen(tempG),G);
    send(clientSocket,G,lenOfG,0);
    // printBase64(G);
    // printf("\n");
    printf("消息G发送完成\n");

    //等待消息H
    printf("等待接收消息H\n");
    char tempH[200];
    char H[200];
    char tempID[200];
    int lenOftempH = recv(clientSocket,tempH,200,0);
    printf("消息H接收完成，开始解密\n");
    rdes(Ksession_Client_SS,tempH,lenOftempH,H);
    printf("解密后H %s\n",H);

    sscanf(H,"%[^,],%ld",tempID,&timestamp2);
    printf("%ld,%ld\n",timestamp1,timestamp2);

    if(timestamp2 - timestamp1 == 1){
        printf("可以信赖\n");
        printf("----------第三阶段结束----------\n");
        printf("----------认证结束 可信通信----------\n");
    }else{
        printf("----------SS服务器不可信赖---------\n");
        return;
    }
}